# coding=utf-8
import json
import watchdog

__author__ = 'Jiang Le'

from watchdog.events import FileSystemEventHandler, os
from watchdog.observers import Observer
from tools import Tools


class FileChangeEventHandler(FileSystemEventHandler):
    def __init__(self, src):
        FileSystemEventHandler.__init__(self)
        self.ingored_folder = [".sunjian"]
        self.hold_file = [".md"]
        self.src = src
        self.list_path = os.path.join(self.src, ".sunjian/list.json")
        self.update_path = os.path.join(self.src, ".sunjian/update.json")

    # 假定path已经去除prefix
    def json_add(self, path):
        d = {}
        with open(self.list_path, "r") as f:
            json_string = f.read()
        if json_string.strip():
            d = json.loads(json_string)
        info = Tools.getFileInfo(self.src, path)
        d.update(info)
        json.dump(d, open(self.list_path, "w"))
        return d

    def json_delete(self, path):
        # 默认认为删除文件时，list.json中不可能没有内容，所以不再判断
        with open(self.list_path, "r") as f:
            json_string = f.read()
        d = json.loads(json_string)
        keys = d.keys()
        for key in keys:
            if key.startswith(path):
                if d.pop(key, -1) == -1:
                    print u"删除失败"
        json.dump(d, open(self.list_path, "w"))
        return d

    def json_update_key(self, src_path, dest_path):
        src_path = Tools.pathRegual(self.src, src_path)
        dest_path = Tools.pathRegual(self.src, dest_path)
        self.json_add(dest_path)
        self.json_delete(src_path)

    def json_update_value(self, path):
        self.json_add(path)

    def dispatch(self, event):
            """Dispatches events to the appropriate methods.

            :param event:
                The event object representing the file system event.
            :type event:
                :class:`FileSystemEvent`
            """
            EVENT_TYPE_MOVED = 'moved'
            EVENT_TYPE_DELETED = 'deleted'
            EVENT_TYPE_CREATED = 'created'
            EVENT_TYPE_MODIFIED = 'modified'

            if not self.on_any_event(event):
                return
            _method_map = {
                EVENT_TYPE_MODIFIED: self.on_modified,
                EVENT_TYPE_MOVED: self.on_moved,
                EVENT_TYPE_CREATED: self.on_created,
                EVENT_TYPE_DELETED: self.on_deleted,
            }
            event_type = event.event_type
            _method_map[event_type](event)

    def on_any_event(self, event):

        if isinstance(event, watchdog.events.FileMovedEvent):
            dest_path = event.dest_path
        else:
            dest_path = None
        if dest_path:
            return not (self.is_ingored(event.src_path) and self.is_ingored(dest_path))
        else:
            return not self.is_ingored(event.src_path)

    def on_created(self, event):
        """Called when a file or directory is created."""
        if isinstance(event, watchdog.events.FileCreatedEvent):
            self.json_add(event.src_path)
            FileChangeEventHandler.update_add(self.src, [event.src_path])

    def on_deleted(self, event):
        """Called when a file or directory is deleted."""
        self.json_delete(Tools.decode(event.src_path))
        FileChangeEventHandler.update_delete(self.src, [event.src_path])

    # 从list.json中获得删除目录下的所有文件
    def get_files(self, path):
        with open(self.list_path, "r") as f:
            json_string = f.read()
        d = json.loads(json_string)
        keys = d.keys()
        delete_file = []
        for key in keys:
            if key.startswith(path):
                delete_file.append(key)
        return delete_file

    def on_moved(self, event):
        """Called when a file or a directory is renamed."""
        # 当文件夹重命名时，文件夹下的所有文件也会触发重命名事件，所以就忽略文件夹的重命名事件
        # and not event.is_directory
        if isinstance(event, watchdog.events.FileMovedEvent) and not event.is_directory:
            self.json_update_key(event.src_path, event.dest_path)
            FileChangeEventHandler.update_delete(self.src, [event.src_path])
            FileChangeEventHandler.update_add(self.src, [event.dest_path])

    def on_modified(self, event):
        if isinstance(event, watchdog.events.FileModifiedEvent):
            self.json_update_value(Tools.decode(event.src_path))
            FileChangeEventHandler.update_add(self.src, [event.src_path])

    def is_ingored(self, path):
        path_list = path.split(os.sep)
        for fold in self.ingored_folder:
            if fold in path_list:
                return True
        # 已经对文件夹进行了过滤，如果仍然是文件夹就不用忽略了
        if os.path.splitext(path)[1] == "":
            return False
        if os.path.splitext(path)[1] not in self.hold_file:
            return True
        return False

    @staticmethod
    def update_add(src, add_path_list):
        p = os.path.join(src, ".sunjian")
        if not os.path.exists(p):
            os.mkdir(p)
        with open(os.path.join(p, "update.json"), "a+") as f:
            string = f.read()
        d = {}
        if string.strip():
            d = json.loads(string)
        s = set(d.get("add", ""))
        for path in add_path_list:
            path = Tools.pathRegual(src, path)
            s.add(path)
        d.update({"add": list(s)})
        json.dump(d, open(os.path.join(p, "update.json"), "w"))

    @staticmethod
    def update_delete(src, del_path_list):
        p = os.path.join(src, ".sunjian")
        if not os.path.exists(p):
            os.mkdir(p)
        with open(os.path.join(p, "update.json"), "a+") as f:
            string = f.read()
        d = {}
        if string.strip():
            d = json.loads(string)
        s = set(d.get("del", ""))
        for path in del_path_list:
            path = Tools.pathRegual(src, path)
            s.add(path)
        d.update({"del": list(s)})
        json.dump(d, open(os.path.join(p, "update.json"), "w"))

class UpDataer():
    def __init__(self, src):
        self.src = src
        handler = FileChangeEventHandler(self.src)
        self.observer = Observer()
        self.observer.schedule(handler, self.src, recursive=True)

    def start(self):
        self.observer.start()
        print "Waiting"
        # try:
        #     while True:
        #         time.sleep(1)
        # except KeyboardInterrupt:
        #     self.observer.stop()
        # self.observer.join()
